package com.hepinghospital.user.service;

import android.annotation.SuppressLint;
import android.app.Notification;
import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.os.Build;
import android.os.Handler;
import android.os.IBinder;
import android.util.Log;

import androidx.annotation.Nullable;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.hepinghospital.user.R;
import com.hepinghospital.user.base.BaseApplication;
import com.hepinghospital.user.eventbus.Logout;
import com.hepinghospital.user.eventbus.WebSocket;
import com.hepinghospital.user.eventbus.WebSocketWrapper;
import com.hepinghospital.user.ui.activity.consult.ChatActivity;
import com.hepinghospital.user.ui.activity.consult.DialogActivity;
import com.hepinghospital.user.util.JWebSocketClient;
import com.hepinghospital.user.util.ToastUtil;
import com.rest.client.RestClient;
import com.rest.constant.JDConstant;
import com.rest.response.ChatResponse;

import org.greenrobot.eventbus.EventBus;
import org.greenrobot.eventbus.Subscribe;
import org.greenrobot.eventbus.ThreadMode;
import org.java_websocket.handshake.ServerHandshake;

import java.net.URI;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;

import jz.joyoung.robot.util.LogUtil;
import jz.joyoung.robot.util.PreferencesHelper;
import jz.joyoung.robot.util.TimeUtil;
import jz.joyoung.robot.util.UIConstants;

/**
 * Created by Administrator on 2020/2/11.
 */

public class WebSocketService extends Service {
    public JWebSocketClient client;

    ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(1, 1, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<>(), r -> {
        AtomicInteger threadNum = new AtomicInteger(1);
        Thread t = new Thread(r);
        String name = "WebSocket_Thread-" + threadNum.getAndIncrement();
        t.setName(name);
        t.setPriority(Thread.NORM_PRIORITY);
        return t;
    });

    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }

    @Override
    public void onCreate() {
        super.onCreate();
        //开启前台Service
        startForeground(this);
        System.out.println("start service");
        if (!EventBus.getDefault().isRegistered(this)) {
            EventBus.getDefault().register(this);
        }
        mHandler.postDelayed(heartBeatRunnable, HEART_BEAT_RATE);
        mHandler.postDelayed(repeatMessageRunnable, 5000);
    }


    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        initSocketClient();
        return START_STICKY;
    }


    private void initSocketClient() {
        if (null == BaseApplication.currentUserId) {
            return;
        }
        URI uri = URI.create(JDConstant.WEBSOCKET_HOST + "imserver?username=" + BaseApplication.currentUserId);
        client = new JWebSocketClient(uri) {
            @Override
            public void onMessage(String message) {
                Log.e("JWebSocketClientService", "收到的消息：" + message);
                WebSocketWrapper obj = JSONObject.parseObject(message, WebSocketWrapper.class);
                if (obj.command == UIConstants.WEBSOCKET_COMMAND_11) {
                    obj.data.eventFlag = 0;
                    WebSocketCmd cmd = new WebSocketCmd("21", 0, BaseApplication.currentUserId, obj.data.id, obj.data.id);
                    sendMsg(JSONObject.toJSONString(cmd));
                    EventBus.getDefault().postSticky(obj.data);
                } else if (obj.cmd == UIConstants.WEBSOCKET_CMD_100) {
                    //加入会议
                    if (BaseApplication.isPhoning) {
                        @SuppressLint("SimpleDateFormat") SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");//设置日期格式
                        String clientId = TimeUtil.getClientId();
                        ChatResponse.Message myMessage = new ChatResponse().new Message();
                        myMessage.fromType = 0;
                        myMessage.sendTime = df.format(new Date());
                        myMessage.messageId = clientId;
                        myMessage.flag = 1;
                        WebSocket webSocket = new WebSocket.Builder().diagnoseId(obj.diagnoseId).from(BaseApplication.currentUserId).eventFlag(5).to(obj.doctorUserId).msgId(clientId).build();
                        EventBus.getDefault().postSticky(webSocket);
                        return;
                    }
                    EventBus.getDefault().postSticky(obj);
                    Intent mIntent = new Intent(WebSocketService.this, ChatActivity.class);
                    mIntent.putExtra("wsObj", obj);
                    mIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                    startActivity(mIntent);
                } else if (obj.cmd == UIConstants.WEBSOCKET_CMD_101 || obj.cmd == UIConstants.WEBSOCKET_CMD_209) {
                    EventBus.getDefault().postSticky(obj);
                    WebSocketCmd cmd = new WebSocketCmd("21", 0, BaseApplication.currentUserId, obj.id, obj.id);
                    sendMsg(JSONObject.toJSONString(cmd));
                    Intent mIntent = new Intent(WebSocketService.this, DialogActivity.class);
                    mIntent.putExtra("wsObj", obj);
                    mIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                    startActivity(mIntent);
                } else if (obj.command == UIConstants.WEBSOCKET_COMMAND_20) {
                    //{"code":10016,"command":20,"data":{"friends":{},"groups":{},"userid":"1467817210772049922"},"msg":"get user message ok! 获取离线消息成功!"}
                    handlerOfflineMessage(message);
                } else if (obj.cmd == UIConstants.WEBSOCKET_CMD_105) {
                    EventBus.getDefault().postSticky(obj);
                } else if (obj.cmd == UIConstants.WEBSOCKET_CMD_106) {
                    //被挤掉{"cmd":106,"content":"您的账号在其它地方登入"}
                    closeConnect();
                    EventBus.getDefault().postSticky(new Logout(1));
                    RestClient.getInstance().clearSession();
                    BaseApplication.currentUserId = "";
                    RestClient.getInstance().token = "";
                    PreferencesHelper.getInstance().set(WebSocketService.this, "accessToken", "");
                    mHandler.post(() -> ToastUtil.showToast(WebSocketService.this, "你的账号在其他设备登录"));
//                    startActivity( new Intent( WebSocketService.this, LoginActivity.class ) );
                } else if (obj.cmd == UIConstants.WEBSOCKET_CMD_107) {
                    WebSocketCmd cmd = new WebSocketCmd("21", 0, BaseApplication.currentUserId, obj.id, obj.id);
                    sendMsg(JSONObject.toJSONString(cmd));
                    mHandler.post(() -> ToastUtil.showToast(WebSocketService.this, "你的处方已通过审核"));
                } else if (obj.cmd == UIConstants.WEBSOCKET_CMD_108) {
                    EventBus.getDefault().postSticky(obj);
                    WebSocketCmd cmd = new WebSocketCmd("21", 0, BaseApplication.currentUserId, obj.id, obj.id);
                    sendMsg(JSONObject.toJSONString(cmd));
                    mHandler.post(() -> ToastUtil.showToast(WebSocketService.this, "医生已接受你的图文咨询"));
                } else if (obj.cmd == UIConstants.WEBSOCKET_CMD_208) {
                    EventBus.getDefault().postSticky(obj);
                    WebSocketCmd cmd = new WebSocketCmd("21", 0, BaseApplication.currentUserId, obj.id, obj.id);
                    sendMsg(JSONObject.toJSONString(cmd));
                    mHandler.post(() -> ToastUtil.showToast(WebSocketService.this, "医生已接受你的护理咨询"));
                } else if (obj.cmd == UIConstants.WEBSOCKET_CMD_109) {
                    EventBus.getDefault().postSticky(obj);
                    WebSocketCmd cmd = new WebSocketCmd("21", 0, BaseApplication.currentUserId, obj.id, obj.id);
                    sendMsg(JSONObject.toJSONString(cmd));
                } else if (obj.cmd == UIConstants.WEBSOCKET_CMD_110) {
                    EventBus.getDefault().postSticky(obj);
                    WebSocketCmd cmd = new WebSocketCmd("21", 0, BaseApplication.currentUserId, obj.id, obj.id);
                    sendMsg(JSONObject.toJSONString(cmd));
                } else if (obj.cmd == UIConstants.WEBSOCKET_CMD_112) { //处方状态变更
                    WebSocketCmd cmd = new WebSocketCmd("21", 0, BaseApplication.currentUserId, obj.id, obj.id);
                    sendMsg(JSONObject.toJSONString(cmd));
                    EventBus.getDefault().postSticky(obj);
//                    mHandler.post( () -> ToastUtil.showToast( WebSocketService.this, "医生正在开处方，大约需要等待5分钟" ) );
                } else if (obj.cmd == UIConstants.WEBSOCKET_CMD_211 || obj.cmd == UIConstants.WEBSOCKET_CMD_212) {
                    WebSocketCmd cmd = new WebSocketCmd("21", 0, BaseApplication.currentUserId, obj.id, obj.id);
                    sendMsg(JSONObject.toJSONString(cmd));
                    EventBus.getDefault().postSticky(obj);
                } else if (obj.code == 10000) {
                    EventBus.getDefault().postSticky(obj);
                    BaseApplication.runningCalls.remove(obj.clientId);
                } else if (obj.code == 10001) {
                    EventBus.getDefault().postSticky(obj);
                    BaseApplication.runningCalls.remove(obj.clientId);
                } else if (obj.cmd == UIConstants.WEBSOCKET_CMD_114 || obj.cmd == UIConstants.WEBSOCKET_CMD_115) {
                    EventBus.getDefault().postSticky(obj);
                }
            }

            @Override
            public void onClose(int code, String reason, boolean remote) {
                super.onClose(code, reason, remote);
                Log.e("JWebSocketClientService", reason);
            }

            @Override
            public void onOpen(ServerHandshake handshakedata) {
                super.onOpen(handshakedata);
                Log.e("JWebSocketClientService", "websocket连接成功");
                WebSocketCmd cmd = new WebSocketCmd("19", 0, BaseApplication.currentUserId, "", "");
                sendMsg(JSONObject.toJSONString(cmd));
            }
        };
        connect();
        client.setConnectionLostTimeout(0);
    }


    private void handlerOfflineMessage(String message) {
        //{"code":10016,"command":20,"data":{"friends":{},"groups":{},"userid":"1467817210772049922"},"msg":"get user message ok! 获取离线消息成功!"}

        JSONObject jsonObject = JSONObject.parseObject(message);
        JSONObject data = jsonObject.getJSONObject("data");
        JSONObject friends = data.getJSONObject("friends");

        Map<String, Object> map = new HashMap<>();
        for (Map.Entry<String, Object> entry : friends.entrySet()) {
            map.put(entry.getKey(), entry.getValue());
        }

        for (Map.Entry<String, Object> entry : map.entrySet()) {
            String mapKey = entry.getKey();
            String mapValue = entry.getValue().toString();
//            System.out.println(mapKey + ":" + mapValue);
//            System.out.println("------------------------");
            JSONArray array = JSONArray.parseArray(mapValue);
            for (int i = 0; i < array.size(); i++) {

                WebSocketWrapper obj = JSONObject.parseObject(array.getJSONObject(i).toJSONString(), WebSocketWrapper.class);
                if (obj.cmd == UIConstants.WEBSOCKET_CMD_101) {
                    EventBus.getDefault().postSticky(obj);
                    Intent mIntent = new Intent(WebSocketService.this, DialogActivity.class);
                    mIntent.putExtra("wsObj", obj);
                    mIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                    startActivity(mIntent);
                } else if (obj.cmd == UIConstants.WEBSOCKET_CMD_10) {
                    EventBus.getDefault().postSticky(obj);
                } else if (obj.cmd == UIConstants.WEBSOCKET_CMD_100) {
                    //移动视频通话
                    if (BaseApplication.isPhoning) {
                        @SuppressLint("SimpleDateFormat") SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");//设置日期格式
                        String clientId = TimeUtil.getClientId();
                        ChatResponse.Message myMessage = new ChatResponse().new Message();
                        myMessage.fromType = 0;
                        myMessage.sendTime = df.format(new Date());
                        myMessage.messageId = clientId;
                        myMessage.flag = 1;
                        WebSocket webSocket = new WebSocket.Builder().diagnoseId(obj.diagnoseId).from(BaseApplication.currentUserId).eventFlag(5).to(obj.doctorUserId).msgId(clientId).build();
                        EventBus.getDefault().postSticky(webSocket);
                        return;
                    }

                    EventBus.getDefault().postSticky(obj);
                    Intent mIntent = new Intent(WebSocketService.this, ChatActivity.class);
                    mIntent.putExtra("wsObj", obj);
                    mIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                    startActivity(mIntent);
                }
            }
        }

    }

    /**
     * 连接websocket
     */
    private void connect() {
        threadPoolExecutor.execute(() -> {
            try {
                //connectBlocking多出一个等待操作，会先连接再发送，否则未连接发送会报错
                client.connectBlocking();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });
//        new Thread(() -> {
//            try {
//                //connectBlocking多出一个等待操作，会先连接再发送，否则未连接发送会报错
//                client.connectBlocking();
//            } catch (InterruptedException e) {
//                e.printStackTrace();
//            }
//        }).start();
    }

    /**
     * 发送消息
     */
    public void sendMsg(String msg) {
        if (null != client) {
            Log.e("JWebSocketClientService", "发送的消息：" + msg);
            try {
                client.send(msg);
            } catch (Exception e) {

            }
        }
    }

    /**
     * 断开连接
     */
    private void closeConnect() {
        mHandler.removeCallbacks(heartBeatRunnable);
        mHandler.removeCallbacks(repeatMessageRunnable);
        threadPoolExecutor.shutdown();
        try {
            if (null != client) {
                client.close();
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            client = null;
        }
    }

    @Subscribe(threadMode = ThreadMode.MAIN)
    public void onMessageEvent(WebSocket webSocket) {
        if (webSocket.eventFlag == 1) {
            webSocket.createTime = System.currentTimeMillis() + "";
            webSocket.roleType = 0;
            webSocket.chatType = 2;
            webSocket.cmd = 11;
            sendMsg(JSONObject.toJSONString(webSocket));
            BaseApplication.runningCalls.put(webSocket.clientId, webSocket);
        } else if (webSocket.eventFlag == 4) {
            sendMsg(JSONObject.toJSONString(webSocket));
        } else if (webSocket.eventFlag == 5) {
            webSocket.cmd = 30;
            sendMsg(JSONObject.toJSONString(webSocket));
        }
    }


    @Override
    public void onDestroy() {
        LogUtil.e("服务onDestroy方法");
        if (EventBus.getDefault().isRegistered(this)) {
            EventBus.getDefault().unregister(this);
        }
        closeConnect();
        super.onDestroy();
    }


    private final long HEART_BEAT_RATE = 10 * 1000;//每隔10秒进行一次对长连接的心跳检测

    private Handler mHandler = new Handler();
    private Runnable heartBeatRunnable = new Runnable() {
        @Override
        public void run() {
            if (client != null) {
                if (client.isClosed()) {
                    reconnectWs();
                } else {
                    sendMsg("{'cmd':13,'hbbyte':'heartbeat'}");
                }
            } else {
                //如果client已为空，重新初始化websocket
                initSocketClient();
            }
            //定时对长连接进行心跳检测
            mHandler.postDelayed(this, HEART_BEAT_RATE);
        }
    };
    private Runnable repeatMessageRunnable = new Runnable() {
        @Override
        public void run() {
            for (Map.Entry<String, WebSocket> entry : BaseApplication.runningCalls.entrySet()) {
                sendMsg(JSONObject.toJSONString(entry.getValue()));
            }
            mHandler.postDelayed(this, 5000);
        }
    };

    /**
     * 开启重连
     */
    private void reconnectWs() {
        mHandler.removeCallbacks(heartBeatRunnable);
        threadPoolExecutor.execute(() -> {
            try {
                //重连
                client.reconnectBlocking();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });
//
//        new Thread(() -> {
//            try {
//                //重连
//                client.reconnectBlocking();
//            } catch (InterruptedException e) {
//                e.printStackTrace();
//            }
//        }).start();
    }

    /**
     * 判断client状态
     *
     * @time 2020/3/30 14:53
     */

    private void showClientStatus() {
        if (client != null) {
            if (client.isClosed()) {
                reconnectWs();
            } else {
                sendMsg("{'cmd':13,'hbbyte':'heartbeat'}");
            }
        } else {
            //如果client已为空，重新初始化websocket
            initSocketClient();
        }
    }

    public static void startForeground(Service service) {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            //适配安卓8.0
            NotificationChannel channel = new NotificationChannel("WebSocketService", "WebSocketService", NotificationManager.IMPORTANCE_MIN);
            channel.enableVibration(false);//去除振动

            NotificationManager manager = (NotificationManager) service.getSystemService(Context.NOTIFICATION_SERVICE);
            assert manager != null;
            manager.createNotificationChannel(channel);
            Notification.Builder builder = new Notification.Builder(service.getApplicationContext(), "WebSocketService")
//                    .setContentTitle("正在后台运行")
                    .setSmallIcon(R.mipmap.icon);
            service.startForeground(1, builder.build());//id must not be 0,即禁止是0
            service.stopForeground(true);
        }
    }
}
